package best.driver.android.common.network;

import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import best.driver.android.Activity.Login.Login;
import best.driver.android.AppConfig;
import best.driver.android.AppInfo;
import best.driver.android.BestApp;
import best.driver.android.Utils.PhoneFunc;
import best.driver.android.volley.AuthFailureError;
import best.driver.android.volley.Response;
import best.driver.android.volley.VolleyError;
import best.driver.android.volley.toolbox.JsonObjectRequest;
import best.driver.android.manager.UserInfoManager;
import org.json.JSONObject;


import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

public abstract class ApiRequest<T> {

    public enum Method {
        GET,
        POST
    }

    //请求监听器
    public static interface ApiRequestListener<T> {
        /**
         * 请求成功回调
         *
         * @param response 服务响应数据
         */
        void onRequestSuccess(T response);

        /**
         * 请求失败回调
         *
         * @param error 请求错误,可能为网络错误或者业务调用错误
         */
        void onRequestError(BestError error);
    }

    public static interface ApiRequestErrorFilter {

        public boolean shouldFilterError(BestError error);

    }

    public static final String TAG = "ApiRequest";

    private static ApiRequestErrorFilter sErrorFilter;
    private ApiRequestListener<T> mListener;
    private boolean mCanceled;
    private Method mMethod;
    private String mUrl;
    private Map<String, Object> mParams;
    JsonObjectRequest mRequest;

    public static void registerErrorFilter(Class cls) {
        try {
            sErrorFilter = (ApiRequestErrorFilter) cls.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public ApiRequest(Method method) {
        this.mMethod = method;
    }

    public Method getMethod() {
        return mMethod;
    }

    public void setMethod(Method method) {
        mMethod = method;
    }

    public String getUrl() {
        return mUrl;
    }

    public void setUrl(String url) {
        mUrl = url;
    }

    public Map<String, Object> getParams() {
        return mParams;
    }


    public void setParams(Map<String, Object> params) {
        mParams = params;
    }

    JsonObjectRequest getRequest() {
        if (mRequest == null) {
            Response.Listener<JSONObject> listener = new VolleyListenerImpl();
            Response.ErrorListener errorListener = new VolleyErrorListenerImpl();

            int methodCode = getMethod() == Method.GET ? 0 : 1;
            mRequest = new VolleyJsonObjectRequest(methodCode, getUrl(), getParams(), listener, errorListener) {
                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    return getHeaderParam();
                }

            };

            Log.d(TAG, "make request:" + getMethod() + "," + mRequest.getUrl());
        }

        return mRequest;
    }

    private Map<String, String> getHeaderParam(){
        HashMap<String, String> headerMap = new HashMap<String, String>();
        headerMap.put("useragent", AppConfig.APP_VERSION +";"+ Build.MODEL + ";Android/" +Build.VERSION.RELEASE +";"+ "WIFI;" + PhoneFunc.getImei());
        headerMap.put("Content-Type", "application/json");
        headerMap.put("access-token", UserInfoManager.getInstance().getToken());
        return headerMap;
    }


    public ApiRequestListener<T> getListener() {
        return mListener;
    }

    public void setListener(ApiRequestListener<T> listener) {
        mListener = listener;
    }

    /**
     * 取消请求，回调不会再调用
     */
    public void cancel() {
        mCanceled = true;
        mRequest.cancel();
    }

    public boolean isCanceled() {
        return mCanceled;
    }

    protected abstract T processJsonResponse(Object response);

    /**
     * 通知请求失败
     *
     * @param error 请求错误
     */
    protected void notifyError(BestError error) {
        if (!isCanceled() && getListener() != null) {
            if (sErrorFilter == null || !sErrorFilter.shouldFilterError(error)) {
                getListener().onRequestError(error);
        		try {
					if (error != null && !(error instanceof BestApiError)) {
                        if(!TextUtils.isEmpty(error.getMessage())) {
                            AppInfo.showToast(BestApp.getInstance(), error.getMessage());
                        } else {
                            if(error instanceof BestNetworkError && ((BestNetworkError)error).getVolleyError().getNetworkTimeMs() == -11) {

                            } else {
                                AppInfo.showToast(BestApp.getInstance(), "网络连接出错，请检查网络");
                            }
                        }
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
        	
            }
        }
    }

    protected void notifySuccess(T response) {
        if (!isCanceled() && getListener() != null) {
            getListener().onRequestSuccess(response);
        }
    }

    private void handleJsonResponse(JSONObject response) {
        if (null == response) {
            return;
        }
        String errorCode = response.optString("success", "");

        if (errorCode.equals(CallBackStatus.SUCCESS)) {
            T data = processJsonResponse(response.opt("result"));
            notifySuccess(data);
//        } else if (errorCode == 100 && !((BestApp.getInstance().getLastActivity() instanceof SplashActivity)
//               || BestApp.getInstance().getLastActivity() instanceof LoginActivity)) {
//            if(BackgroundUtils.getInstance().isAppOnForeground()) {
//                AppInfo.showToast(BestApp.getInstance().getApplicationContext(), "帐号已过期，请重新登陆");
//                BestApp.getInstance().finishHomeActivity();
//                Intent intent = new Intent(BestApp.getInstance().getApplicationContext(), SplashActivity.class);
//                UserInfoManager.getInstance().setLogin(false);
//                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                BestApp.getInstance().getApplicationContext().startActivity(intent);
//            }
        } else if (errorCode.equals("")){
            return;
        } else if (errorCode.equals(CallBackStatus.FAIL)){
            String errorMessage = response.optString("error");
            if("Access-Token-Invalid".equals(errorMessage)) {
                BestApp.getInstance().finishAllActivities();
                AppInfo.showToast(BestApp.getInstance().getApplicationContext(), "token过期，请重新登录");
                UserInfoManager.getInstance().clearUserInfo();
                BestApp.getInstance().startActivity(new Intent(BestApp.getInstance().getApplicationContext(), Login.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                return;
            }
            BestApiError apiError = new BestApiError(errorCode, errorMessage);
            notifyError(apiError);
        }
    }

    private class VolleyListenerImpl implements Response.Listener<JSONObject> {
        @Override
        public void onResponse(JSONObject response) {
            Log.d(TAG, "json response:" + response);

            handleJsonResponse(response);
        }
    }


    private class VolleyErrorListenerImpl implements Response.ErrorListener {
        @Override
        public void onErrorResponse(VolleyError error) {
            StringBuffer sb = new StringBuffer();
            if (error.networkResponse != null && error.networkResponse.data != null) {
                try {
                    sb.append(new String(error.networkResponse.data, "utf-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }

            Log.d(TAG, "error:" + error + ",response:" + sb.toString());

            BestNetworkError choiceError = new BestNetworkError(error);
            notifyError(choiceError);
        }
    }

    @Override
    public String toString() {
        return "ApiRequest{" +
                ", mMethod=" + mMethod +
                ", mUrl='" + mUrl + '\'' +
                "'}";
    }

    public class VolleyJsonObjectRequest extends JsonObjectRequest {

        private Map<String, String> mHeaders;
        private Map<String, Object> mParams;

        public VolleyJsonObjectRequest(int method, String url, Map<String, Object> params, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
            super(method, url, null, listener, errorListener);
            mParams = params;
        }

        public VolleyJsonObjectRequest(String url, Map<String, Object> params, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
            super(url, null, listener, errorListener);
            mParams = params;
        }


        @Override
        public byte[] getBody() {
            if (mParams != null && mParams.size() > 0) {
                return encodeParameters(mParams, getParamsEncoding());
            }

            return null;
        }

//        @Override
//        public String getBodyContentType() {
//            return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
//        }

        private byte[] encodeParameters(Map<String, Object> params, String paramsEncoding) {
            StringBuilder encodedParams = new StringBuilder();
            try {
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                    encodedParams.append(':');
                    encodedParams.append('"');
                    encodedParams.append(URLEncoder.encode(String.valueOf(entry.getValue()), paramsEncoding));
                    encodedParams.append('"');
                    encodedParams.append(',');
                }
                encodedParams.delete(encodedParams.length()-1, encodedParams.length());
                //JSONStr
                JSONObject object = new JSONObject(params);
                return object.toString().getBytes(paramsEncoding);
            } catch (UnsupportedEncodingException uee) {
                throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
            }
        }
    }
}
